﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Tools.Ribbon;
using System.IO;
using System.Windows.Forms;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace TFSWordAddIn
{
    public partial class TeamRibbon
    {
        TfsTeamProjectCollection _tfsCollection = null;
        WorkItemStore _workItemStore = null;
        Office.CustomXMLNode _dummyCData = null;
        Office.CustomXMLNode _dummyNode = null;
        string _workItemsFile;
        string _templateFile;

        private void TeamRibbon_Load(object sender, RibbonUIEventArgs e)
        {

        }

        TfsTeamProjectCollection EnsureTfsConnection(Word.Document activeDoc)
        {
            if (_tfsCollection != null)
                return _tfsCollection;
            else
            {
                Office.CustomXMLPart xmlPart = FindTeamWriterXMLPart(activeDoc);
                if (xmlPart == null)
                    throw new ApplicationException("This document is not linked with TFS");
                string serverUrl = xmlPart.DocumentElement.SelectSingleNode("@serverUrl").NodeValue;

                _tfsCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(serverUrl), new UICredentialsProvider());
                _tfsCollection.Connect(ConnectOptions.IncludeServices);

                return _tfsCollection;
            }
        }

        private void EnsurePaths()
        {
            _workItemsFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamWriter", "WorkItemListIds.xml");
            if (!File.Exists(_workItemsFile))
            {
                MessageBox.Show("Nothing to paste\r\n" + _workItemsFile);
                return;
            }

            _templateFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamWriter\\Templates", "WorkItem Templates.docx");
            if (!File.Exists(_templateFile))
            {
                MessageBox.Show("Template not found\r\n" + _templateFile);
                return;
            }
        }

        private void insertWorkItems_Click(object sender, RibbonControlEventArgs e)
        {
            EnsurePaths();
            Word.Document templateDoc = null;
            Word.Document clipping = null;
            try
            {
                Word.Document activeDoc = ThisAddIn.Addin.Application.ActiveDocument;
                Word.Range selectionRange = ThisAddIn.Addin.Application.Selection.Range;
                selectionRange.Text = "x";
                selectionRange.Text = "";

                templateDoc = ThisAddIn.Addin.Application.Documents.Open(_templateFile, ReadOnly: true, Visible: false);
                if (templateDoc.ContentControls.Count == 0)
                {
                    MessageBox.Show("No Content Control found in template\r\n" + _templateFile);
                    return;
                }

                clipping = InitClipping();

                Microsoft.Office.Core.DocumentProperties props = activeDoc.CustomDocumentProperties as Microsoft.Office.Core.DocumentProperties;

                Office.CustomXMLPart xmlPart = FindOrCreateTeamWriterXMLPart(activeDoc);
                _dummyCData = xmlPart.DocumentElement.SelectSingleNode("DummyCData");
                _dummyNode = xmlPart.DocumentElement.SelectSingleNode("DummyNode");

                using (XmlReader reader = XmlReader.Create(_workItemsFile))
                {
                    reader.MoveToContent();
                    string serverUrl = reader.GetAttribute("serverUrl");
                    RegisterTFSUrl(serverUrl, xmlPart);

                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            if (reader.Name == "WorkItem")
                            {
                                XElement el = XNode.ReadFrom(reader) as XElement;
                                InsertWorkItem(selectionRange, templateDoc, clipping, el, xmlPart);
                            }
                        }
                    }
                }

                CleanXMLPart(activeDoc, xmlPart);

                //foreach (Word.ContentControl contentControl in activeDoc.ContentControls)
                //{
                //    if (contentControl.Tag == "WorkItem")
                //    {
                //        foreach (Word.ContentControl field in contentControl.Range.ContentControls)
                //        {
                //            if (field.Type == Word.WdContentControlType.wdContentControlRichText)
                //            {
                //                Word.Range br = field.Range.Words.Last;
                //                if (br.Text != null && br.Text.Trim() == "")
                //                    br.Delete();
                //            }
                //        }
                //    }
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetBaseException().GetType().Name + " " + ex.GetBaseException().Message + "\r\n\r\n" + ex.StackTrace);

            }
            finally
            {
                if (templateDoc != null)
                    (templateDoc as Microsoft.Office.Interop.Word._Document).Close(SaveChanges: Word.WdSaveOptions.wdDoNotSaveChanges);
                if (clipping != null)
                    (clipping as Microsoft.Office.Interop.Word._Document).Close(SaveChanges: Word.WdSaveOptions.wdDoNotSaveChanges);
                if (_dummyCData != null)
                    _dummyCData.FirstChild.NodeValue = "";
                if (_dummyNode != null)
                    _dummyNode.Text = "";
            }
        }

        /* ORIGINALinsertWorkItems_Click
        private void ORIGINALinsertWorkItems_Click(object sender, RibbonControlEventArgs e)
        {
            Word.Document templateDoc = null;
            Word.Document clipping = null;
            try
            {
                //string htmFile = Path.Combine(Path.GetTempPath(), "teamdoctmp.html");
                //ThisAddIn.Addin.Application.Selection.Range.InsertFile(htmFile, ConfirmConversions: false);
                //return;


                string workitems = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamWriter", "WorkItemList.xml");
                if (!File.Exists(workitems))
                {
                    MessageBox.Show("Nothing to paste\r\n" + workitems);
                    return;
                }

                string template = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamWriter\\Templates", "WorkItem Templates.docx");
                if (!File.Exists(template))
                {
                    MessageBox.Show("Template not found\r\n" + template);
                    return;
                }


                Word.Document activeDoc = ThisAddIn.Addin.Application.ActiveDocument;
                Word.Range selectionRange = ThisAddIn.Addin.Application.Selection.Range;
                selectionRange.Text = "x";
                selectionRange.Text = "";

                templateDoc = ThisAddIn.Addin.Application.Documents.Open(template, ReadOnly: true, Visible: false);
                if (templateDoc.ContentControls.Count == 0)
                {
                    MessageBox.Show("No Content Control found in template\r\n" + template);
                    return;
                }

                clipping = InitClipping();

                Microsoft.Office.Core.DocumentProperties props = activeDoc.CustomDocumentProperties as Microsoft.Office.Core.DocumentProperties;

                Office.CustomXMLPart xmlPart = FindOrCreateTeamWriterXMLPart(activeDoc);

                using (XmlReader reader = XmlReader.Create(workitems))
                {
                    reader.MoveToContent();
                    string serverUrl = reader.GetAttribute("serverUrl");
                    RegisterTFSUrl(serverUrl, xmlPart);

                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            if (reader.Name == "WorkItem")
                            {
                                XElement el = XNode.ReadFrom(reader) as XElement;
                                InsertWorkItem(selectionRange, templateDoc, clipping, el, xmlPart);
                            }
                        }
                    }
                }

                CleanXMLPart(activeDoc, xmlPart);

                foreach (Word.ContentControl contentControl in activeDoc.ContentControls)
                {
                    if (contentControl.Tag == "WorkItem")
                    {
                        foreach (Word.ContentControl field in contentControl.Range.ContentControls)
                        {
                            if (field.Type == Word.WdContentControlType.wdContentControlRichText)
                            {
                                Word.Range br = field.Range.Words.Last;
                                if (br.Text != null && br.Text.Trim() == "")
                                    br.Delete();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetBaseException().GetType().Name + " " + ex.GetBaseException().Message + "\r\n\r\n" + ex.StackTrace);

            }
            finally
            {
                if (templateDoc != null)
                    (templateDoc as Microsoft.Office.Interop.Word._Document).Close(SaveChanges: Word.WdSaveOptions.wdDoNotSaveChanges);
                if (clipping != null)
                    (clipping as Microsoft.Office.Interop.Word._Document).Close(SaveChanges: Word.WdSaveOptions.wdDoNotSaveChanges);
            }
        }
        */

        private static void CleanXMLPart(Word.Document activeDoc, Office.CustomXMLPart xmlPart)
        {
            List<string> contentControls = new List<string>();
            foreach (Word.ContentControl contentControl in activeDoc.ContentControls)
                contentControls.Add(contentControl.ID);
            foreach (Office.CustomXMLNode node in xmlPart.DocumentElement.ChildNodes)
            {
                if (node.BaseName == "WorkItem")
                {
                    string contentControlID = node.SelectSingleNode("@contentControlID").Text;
                    if (!contentControls.Contains(contentControlID))
                    {
                        node.Delete();
                    }
                }
            }
        }

        private Word.Document InitClipping()
        {
            Word.Style origen = ThisAddIn.Addin.Application.ActiveDocument.Styles["Normal"];
            Word.Style dest = ThisAddIn.Addin.Application.ActiveDocument.Styles["Normal (Web)"];
            origen = ThisAddIn.Addin.Application.ActiveDocument.Styles["Normal"];
            dest.Font = origen.Font;

            string clippingPath = Path.Combine(Path.GetTempPath(), "clipping.htm");
            if (File.Exists(clippingPath))
                File.Delete(clippingPath);
            Word.Document clipping = ThisAddIn.Addin.Application.Documents.Add(DocumentType: Word.WdNewDocumentType.wdNewWebPage, Visible: false);
            clipping.SaveAs2(clippingPath, Word.WdSaveFormat.wdFormatFilteredHTML, AddToRecentFiles: false);
            return clipping;
        }

        private void RegisterTFSUrl(string serverUrl, Office.CustomXMLPart xmlPart)
        {
            Office.CustomXMLNode att = xmlPart.DocumentElement.SelectSingleNode("@serverUrl");
            if (string.IsNullOrEmpty(att.NodeValue))
                att.NodeValue = serverUrl;
            else if (att.NodeValue != serverUrl)
                throw new ApplicationException("You can link a document with only one server. This document is already linked with '" + att.NodeValue + "'");

        }

        private void InsertWorkItem(Word.Range selectionRange, Word.Document template, Word.Document clipping, XElement xmlItem, Office.CustomXMLPart xmlPart)
        {
            string workItemIDString = xmlItem.Attribute("WorkItemID").Value;
            int workItemID = int.Parse(workItemIDString);
            WorkItemStore workItemStore = GetWorkItemStore(selectionRange.Document);
            WorkItem workItem = workItemStore.GetWorkItem(workItemID);

            string type = workItem.Type.Name;
            Word.ContentControls fragments = template.SelectContentControlsByTag(type);
            if (fragments.Count == 0)
                throw new ApplicationException("Content Control template for WorkItemType '" + type + "' not found in \r\n" + template.Path);
            
            Word.ContentControl newContentControl = selectionRange.Document.ContentControls.Add(Type: Word.WdContentControlType.wdContentControlRichText, Range: selectionRange);
            newContentControl.Title = fragments[1].Tag + " " + workItemID;
            newContentControl.Tag = "WorkItem";
            //Office.CustomXMLNode existingWorkItem xmlPart.DocumentElement.SelectSingleNode("WorkItem[@workItemID='" + workItemID + "']");
            xmlPart.DocumentElement.AppendChildSubtree(string.Format(
@"<WorkItem 
  workItemID=""{0}"" 
  workItemRevision=""{1}"" 
  workItemType=""{2}"" 
  contentControlID=""{3}"" />"
                              , workItemID
                              , workItem.Rev
                              , fragments[1].Tag
                              , newContentControl.ID));

            Office.CustomXMLNode workItemCustomNode = xmlPart.DocumentElement.LastChild;

            newContentControl.Range.FormattedText = fragments[1].Range.Duplicate;
            Word.Range range = newContentControl.Range;

            foreach (Word.ContentControl fieldContent in range.ContentControls)
            {
                if (fieldContent.Tag == "WorkItem") continue;
                Field workItemField = workItem.Fields[fieldContent.Tag];
                UpdateFieldControl(fieldContent, clipping, workItemField, workItemCustomNode);
            }
            
            selectionRange.Start = newContentControl.Range.End + 1;
            selectionRange.End = selectionRange.Start;
        }

        /* ORIGINALInsertWorkItem
        private void ORIGINALInsertWorkItem(Word.Range selectionRange, Word.Document template, Word.Document clipping, XElement workItem, Office.CustomXMLPart xmlPart)
        {
            string type = workItem.Attribute("WorkItemType").Value;
            Word.ContentControls fragments = template.SelectContentControlsByTag(type);
            if (fragments.Count == 0)
                throw new ApplicationException("Content Control template for WorkItemType '" + type + "' not found in \r\n" + template.Path);

            Word.ContentControl newContentControl = selectionRange.Document.ContentControls.Add(Type: Word.WdContentControlType.wdContentControlRichText, Range: selectionRange);
            newContentControl.Title = fragments[1].Tag + " " + workItem.Attribute("WorkItemID").Value;
            newContentControl.Tag = "WorkItem";
            string workItemID = workItem.Attribute("WorkItemID").Value;
            //Office.CustomXMLNode existingWorkItem xmlPart.DocumentElement.SelectSingleNode("WorkItem[@workItemID='" + workItemID + "']");
            xmlPart.DocumentElement.AppendChildSubtree(string.Format(
@"<WorkItem 
  workItemID=""{0}"" 
  workItemRevision=""{1}"" 
  workItemType=""{2}"" 
  contentControlID=""{3}"" />"
                              , workItemID
                              , workItem.Attribute("WorkItemRevision").Value
                              , fragments[1].Tag
                              , newContentControl.ID));

            Office.CustomXMLNode workItemCustomNode = xmlPart.DocumentElement.LastChild;

            newContentControl.Range.FormattedText = fragments[1].Range.Duplicate;
            Word.Range range = newContentControl.Range;

            foreach (Word.ContentControl field in range.ContentControls)
            {
                XElement valueNode = workItem.XPathSelectElement("Field[@name='" + field.Tag + "']");

                if (valueNode == null)
                    continue;

                var fieldType = Enum<FieldType>.Parse(valueNode.Attribute("fieldType").Value);
                object val = XmlConvert2.ToObject(valueNode.Value, fieldType);

                UpdateFieldControl(field, clipping, val, fieldType, workItemCustomNode);
            }

            selectionRange.Start = newContentControl.Range.End + 1;
            selectionRange.End = selectionRange.Start;
        }
        */
        
        private static string RangeToHtml(Word.Document clipping, Word.ContentControl fragment)
        {
            string htmlfragment = "";
            clipping.Range().FormattedText = fragment.Range.Duplicate;
            foreach (Word.Frame frame in clipping.Frames)
                frame.Delete();
            clipping.SaveAs2(clipping.FullName, Word.WdSaveFormat.wdFormatFilteredHTML, AddToRecentFiles: false);
            using (FileStream f = File.Open(clipping.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                StreamReader r = new StreamReader(f, Encoding.Default);
                string exportedhtml = r.ReadToEnd();
                int i = exportedhtml.IndexOf("<div", StringComparison.CurrentCultureIgnoreCase);
                i = exportedhtml.IndexOf(">", i);
                int j = exportedhtml.LastIndexOf("</div>", StringComparison.CurrentCultureIgnoreCase);
                htmlfragment = exportedhtml.Substring(i + 1, j - (i + 1));
                string deadend = "\r\n\r\n<p class=MsoNormal>&nbsp;</p>\r\n\r\n";
                if (htmlfragment.EndsWith(deadend))
                    htmlfragment = htmlfragment.Substring(0, htmlfragment.Length - deadend.Length);

            }
            return htmlfragment;
        }

        Office.CustomXMLPart FindOrCreateTeamWriterXMLPart(Word.Document activeDoc)
        {
            Office.CustomXMLPart xmlPart = FindTeamWriterXMLPart(activeDoc);
            if (xmlPart != null) return xmlPart;
        
            return activeDoc.CustomXMLParts.Add(@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<TeamWriterData xmlns=""http://TeamWriter/data""
    serverUrl="""">
    <DummyCData xmlns=""""><![CDATA[]]></DummyCData>
    <DummyNode xmlns=""""></DummyNode>
</TeamWriterData>");
        }

        Office.CustomXMLPart FindTeamWriterXMLPart(Word.Document activeDoc)
        {
            foreach (Office.CustomXMLPart part in activeDoc.CustomXMLParts)
            {
                if (!part.BuiltIn && part.NamespaceURI == "http://TeamWriter/data")
                    return part;
            }
            return null;
        }

        private void button1_Click(object sender, RibbonControlEventArgs e)
        {
            Office.CustomXMLPart xmlPart = FindOrCreateTeamWriterXMLPart(ThisAddIn.Addin.Application.ActiveDocument);
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(xmlPart.XML);
            StringBuilder xmlString = new StringBuilder();
            XmlWriter writer = XmlWriter.Create(xmlString, new XmlWriterSettings() { Indent = true, NewLineOnAttributes = false });
            xml.Save(writer);

            Word.Document doc = ThisAddIn.Addin.Application.Documents.Add();
            doc.Range().Text = xmlString.ToString();
            doc.Range().InsertBefore(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamWriter")+"\r\n\r\n");
            doc.Activate();
        }

        private void publishWorkItems_Click(object sender, RibbonControlEventArgs e)
        {
            Word.Document clipping = null;
            try
            {
                Word.Document activeDoc = ThisAddIn.Addin.Application.ActiveDocument;
                Office.CustomXMLPart xmlPart = FindTeamWriterXMLPart(activeDoc);
                _dummyCData = xmlPart.DocumentElement.SelectSingleNode("DummyCData");
                _dummyNode = xmlPart.DocumentElement.SelectSingleNode("DummyNode");

                clipping = InitClipping();

                string conflicts = "";
                foreach (Word.ContentControl control in activeDoc.SelectContentControlsByTag("WorkItem"))
                {
                    // Inspecting for changes all ContentControls linked to WorkItems
                    WorkItem workItem = null;

                    Office.CustomXMLNode controlNode = xmlPart.DocumentElement.SelectSingleNode("WorkItem[@contentControlID='" + control.ID + "']");
                    string workItemIDString = controlNode.SelectSingleNode("@workItemID").Text;
                    int workItemID = int.Parse(workItemIDString);
                    string revString = controlNode.SelectSingleNode("@workItemRevision").Text;
                    int rev = int.Parse(revString);
                    List<PendingChanges> pendingChanges = new List<PendingChanges>();
                    foreach (Word.ContentControl contentField in control.Range.ContentControls)
                    {
                        if (contentField.Tag == "WorkItem") continue;
                        Office.CustomXMLNode xmlField = controlNode.SelectSingleNode("Field[@name='" + contentField.Tag + "']");
                        FieldType fieldType = Enum<FieldType>.Parse(xmlField.SelectSingleNode("@fieldType").Text);
                        string contentString = ExtractContentAsString(clipping, fieldType, contentField);

                        if (contentString != xmlField.Text)
                        {
                            // Field changed, must publish work item

                            if (workItem == null)
                            {
                                WorkItemStore workItemStore = GetWorkItemStore(activeDoc);
                                workItem = workItemStore.GetWorkItem(workItemID);
                            }

                            bool conflict = false;
                            int revIndex = rev; // index of next revision
                            int revCount = workItem.Revisions.Count;
                            while (revIndex < revCount)
                            {
                                Revision workItemRev = workItem.Revisions[revIndex];
                                Field fieldRev = workItemRev.Fields[contentField.Tag];
                                if (fieldRev.OriginalValue != fieldRev.Value)
                                {
                                    conflict = true;
                                    conflicts += "\r\nWorkItem #" + workItemID + " \"" + (workItem.Title + new string(' ', 20)).Substring(0, 20) + "...\"  Rev: " + (revIndex + 1) + "  Field: " + contentField.Tag;
                                    break;
                                }
                                revIndex += 1;
                            }
                            if (conflict)
                                break; // There is a conflict so we cannot update this field. Try with next one in same work-item.
                            Field itemField = workItem.Fields[contentField.Tag];
                            itemField.Value = Convert.ChangeType(contentString, itemField.FieldDefinition.SystemType);
                            pendingChanges.Add(new PendingChanges() { FieldNode = xmlField, NewValue = contentString });
                        }
                    }
                    if (pendingChanges.Count > 0)
                    {
                        workItem.Save();
                        foreach (PendingChanges change in pendingChanges)
                        {
                            change.FieldNode.FirstChild.NodeValue = change.NewValue;
                        }
                        controlNode.SelectSingleNode("@workItemRevision").Text = workItem.Revision.ToString();
                    }
                }
                if (conflicts != "")
                    MessageBox.Show("Some items not updated because of conflicts\r\n" + conflicts);


                //WorkItemCollection workItems = workItemStore.Query(new int[] { 13, 14 }, "SELECT * FROM Workitems");
                //WorkItem w0 = workItems[0];
                //WorkItem w1 = workItems[1];
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetBaseException().GetType().Name + " " + ex.GetBaseException().Message + "\r\n\r\n" + ex.StackTrace);

            }
            finally
            {
                if (clipping != null)
                    (clipping as Microsoft.Office.Interop.Word._Document).Close(SaveChanges: Word.WdSaveOptions.wdDoNotSaveChanges);
                if (_dummyCData != null)
                    _dummyCData.FirstChild.NodeValue = "";
                if (_dummyNode != null)
                    _dummyNode.Text = "";
            }
        }

        private string ExtractContentAsString(Word.Document clipping, FieldType fieldType, Word.ContentControl contentField)
        {
            string contentString = null;
            if (fieldType == FieldType.Html)
            {
                string htmlfragment = RangeToHtml(clipping, contentField);
                _dummyCData.FirstChild.NodeValue = htmlfragment;
                contentString = _dummyCData.Text;
            }
            else
            {
                _dummyNode.Text = contentField.Range.Text.Replace('\v','\n');
                contentString = _dummyNode.Text;
            }
            return contentString;
        }



        private WorkItemStore GetWorkItemStore(Word.Document activeDoc)
        {
            if (_workItemStore == null)
            {
                TfsTeamProjectCollection tfscol = EnsureTfsConnection(activeDoc);
                WorkItemStore workItemStore = tfscol.GetService<WorkItemStore>();
                return workItemStore;
            }
            else
                return _workItemStore;
        }

        private void refreshWorkItems_Click(object sender, RibbonControlEventArgs e)
        {
            Word.Document clipping = null;
            try
            {
                Word.Document activeDoc = ThisAddIn.Addin.Application.ActiveDocument;
                Office.CustomXMLPart xmlPart = FindTeamWriterXMLPart(activeDoc);
                _dummyCData = xmlPart.DocumentElement.SelectSingleNode("DummyCData");
                _dummyNode = xmlPart.DocumentElement.SelectSingleNode("DummyNode");

                clipping = InitClipping();

                string pendingChanges = CheckPendingChanges(clipping, activeDoc, xmlPart);
                if (pendingChanges != "")
                {
                    if (DialogResult.No == MessageBox.Show("Some items has changes that has not been commited to TFS.\r\n\r\nRefresh and discart Changes?\r\n\r\n" + (pendingChanges + new string(' ', 200).Substring(0, 200)), "Confirm", MessageBoxButtons.YesNo) )
                    return;
                }
                Word.ContentControls allWorkItemContentControls = activeDoc.SelectContentControlsByTag("WorkItem");
                foreach (Word.ContentControl control in allWorkItemContentControls)
                {
                    // Load each work item from server and update Content Controls
                    WorkItem workItem = null;

                    Office.CustomXMLNode controlNode = xmlPart.DocumentElement.SelectSingleNode("WorkItem[@contentControlID='" + control.ID + "']");
                    string workItemIDString = controlNode.SelectSingleNode("@workItemID").Text;
                    int workItemID = int.Parse(workItemIDString);
                    WorkItemStore workItemStore = GetWorkItemStore(activeDoc);
                    workItem = workItemStore.GetWorkItem(workItemID);
                    controlNode.SelectSingleNode("@workItemRevision").NodeValue = workItem.Revision.ToString();
                    foreach (Office.CustomXMLNode child in controlNode.ChildNodes)
                        controlNode.RemoveChild(child);

                    foreach (Word.ContentControl field in control.Range.ContentControls)
                    {
                        if (field.Tag == "WorkItem") continue;
                        Field workItemField = workItem.Fields[field.Tag];
                        UpdateFieldControl(field, clipping, workItemField, controlNode);
                    }

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetBaseException().GetType().Name + " " + ex.GetBaseException().Message + "\r\n\r\n" + ex.StackTrace);

            }
            finally
            {
                if (clipping != null)
                    (clipping as Microsoft.Office.Interop.Word._Document).Close(SaveChanges: Word.WdSaveOptions.wdDoNotSaveChanges);
                if (_dummyCData != null)
                    _dummyCData.FirstChild.NodeValue = "";
                if (_dummyNode != null)
                    _dummyNode.Text = "";
            }
        }

        private string CheckPendingChanges(Word.Document clipping, Word.Document activeDoc, Office.CustomXMLPart xmlPart)
        {
            string pendingChanges = "";
            Word.ContentControls allWorkItemContentControls = activeDoc.SelectContentControlsByTag("WorkItem");
            foreach (Word.ContentControl control in allWorkItemContentControls)
            {
                // Inspecting for changes all ContentControls linked to WorkItems
                Office.CustomXMLNode controlNode = xmlPart.DocumentElement.SelectSingleNode("WorkItem[@contentControlID='" + control.ID + "']");
                string workItemIDString = controlNode.SelectSingleNode("@workItemID").Text;
                int workItemID = int.Parse(workItemIDString);
                string revString = controlNode.SelectSingleNode("@workItemRevision").Text;
                int rev = int.Parse(revString);
                foreach (Word.ContentControl contentField in control.Range.ContentControls)
                {
                    if (contentField.Tag == "WorkItem") continue;
                    Office.CustomXMLNode xmlField = controlNode.SelectSingleNode("Field[@name='" + contentField.Tag + "']");
                    FieldType fieldType = Enum<FieldType>.Parse(xmlField.SelectSingleNode("@fieldType").Text);
                    string contentString = ExtractContentAsString(clipping, fieldType, contentField);

                    if (contentString != xmlField.Text)
                    {
                        pendingChanges += "\r\nWorkItem #" + workItemID + "  Field: " + contentField.Tag;
                    }
                }
            }
            return pendingChanges;
        }
        private void UpdateFieldControl(Word.ContentControl field, Word.Document clipping, Field workItemField, Office.CustomXMLNode workItemCustomNode)
        {
            FieldType type = workItemField.FieldDefinition.FieldType;
            object value = workItemField.Value;
            string text = "";
            string cdata = "";

            //if (field.Type == Word.WdContentControlType.wdContentControlDropdownList && !workItemField.IsLimitedToAllowedValues)
            //{
            //    throw new ApplicationException("Conte Control '"+field.Title+" ("+field.Tag+")' is not valid for work item field ')"+workItemField.Name+". Usa a ComboBox or Text ContentControl instead");
            //}

            if (field.Type == Word.WdContentControlType.wdContentControlText && workItemField.FieldDefinition.FieldType == FieldType.PlainText)
                field.MultiLine = true;

            if (field.Type == Word.WdContentControlType.wdContentControlDropdownList || field.Type == Word.WdContentControlType.wdContentControlComboBox)
            {
                field.DropdownListEntries.Clear();
                text = (string)workItemField.Value;
                foreach (string allowedValue in workItemField.FieldDefinition.AllowedValues)
                {
                    Word.ContentControlListEntry entry = field.DropdownListEntries.Add(allowedValue, allowedValue);
                    if (allowedValue == text)
                        entry.Select();
                }
            }
            else if (type == FieldType.Html)
            {
                // HTML Data Type
                string html = "<html><body>" + value + "</body></html>";
                string htmFile = Path.Combine(Path.GetTempPath(), "teamdoctmp.html");
                File.WriteAllText(htmFile, html, UnicodeEncoding.UTF8);
                field.Range.InsertFile(htmFile, ConfirmConversions: false);

                cdata = RangeToHtml(clipping, field);
            }
            else if (type == FieldType.DateTime)
            {
                if (field.Type == Word.WdContentControlType.wdContentControlDate)
                {
                    field.Range.Text = ((DateTime)value).ToString(field.DateDisplayFormat, new System.Globalization.CultureInfo((int)field.DateDisplayLocale));
                }
                else
                {
                    field.Range.Text = ((DateTime)value).ToString(new System.Globalization.CultureInfo((int)field.Range.LanguageID));
                }
                text = field.Range.Text;
            }
            else if (type == FieldType.Double)
            {
                field.Range.Text = ((double)value).ToString(new System.Globalization.CultureInfo((int)field.Range.LanguageID));
                text = field.Range.Text;
            }
            else if (type == FieldType.Boolean || type == FieldType.String)
            {
                field.Range.Text = value.ToString();
                text = field.Range.Text;
            }
            else // Other Data Types
            {
                field.Range.Text = value.ToString();
                cdata = field.Range.Text.Replace('\v','\n');
            }

            //workItemCustomNode.AppendChildSubtree(string.Format(@"<Field name=""{0}"">{1}</Field>"
            //     , field.Tag
            //     , valueString));
            workItemCustomNode.AppendChildSubtree(string.Format(@"<Field name=""{0}"" fieldType=""{1}""></Field>"
                 , field.Tag
                 , type
                 ));
            if (text != "")
                workItemCustomNode.LastChild.AppendChildNode(NodeType: Office.MsoCustomXMLNodeType.msoCustomXMLNodeText, NodeValue: text);
            else if (cdata != "")
                workItemCustomNode.LastChild.AppendChildNode(NodeType: Office.MsoCustomXMLNodeType.msoCustomXMLNodeCData, NodeValue: cdata);
        }

        private void getWorkItems_Click(object sender, RibbonControlEventArgs e)
        {
            EnsurePaths();

            Word.Document activeDoc = ThisAddIn.Addin.Application.ActiveDocument;
            Office.CustomXMLPart xmlPart=FindTeamWriterXMLPart(activeDoc);
            if (null == xmlPart)
            {
                using (TeamProjectPicker connect = new TeamProjectPicker(TeamProjectPickerMode.NoProject, false))
                {
                    DialogResult res = connect.ShowDialog();
                    if (DialogResult.OK == res)
                    {
                        string serverUrl = connect.SelectedTeamProjectCollection.Uri.AbsoluteUri;
                        xmlPart = FindOrCreateTeamWriterXMLPart(activeDoc);
                        RegisterTFSUrl(serverUrl, xmlPart);
                    }
                    else
                        return;
                }

            }
            WorkItemStore workItemStore = GetWorkItemStore(activeDoc);
            PickWorkItems picker = new PickWorkItems();
            picker.WorkItemStore = workItemStore;

            // Obtain work item IDs in document
            foreach (Word.ContentControl control in activeDoc.SelectContentControlsByTag("WorkItem"))
            {
                Office.CustomXMLNode controlNode = xmlPart.DocumentElement.SelectSingleNode("WorkItem[@contentControlID='" + control.ID + "']");
                string workItemIDString = controlNode.SelectSingleNode("@workItemID").Text;
                int workItemID = int.Parse(workItemIDString);
                picker.ExcludedWorkItemIds.Add(workItemID);
            }

            picker.ShowDialog();

            List<WorkItem> workitems = picker.SelectedWorkItems();
            XmlWriter writer = XmlWriter.Create(_workItemsFile, new XmlWriterSettings() { Indent = true });
            writer.WriteStartElement("WorkItemListIds");
            writer.WriteAttributeString("serverUrl", xmlPart.DocumentElement.SelectSingleNode("@serverUrl").NodeValue);
            foreach (WorkItem item in workitems)
            {
                writer.WriteStartElement("WorkItem");
                writer.WriteAttributeString("WorkItemID", item.Id.ToString());
                writer.WriteEndElement();
            }
            writer.WriteEndElement();
            writer.Close();

            insertWorkItems_Click(null, null);
        }

        /* ORIGINALUpdateFieldControl
        private void ORIGINALUpdateFieldControl(Word.ContentControl field, Word.Document clipping, object value, FieldType type, Office.CustomXMLNode workItemCustomNode)
        {

            if (type == FieldType.Html)
            {
                // HTML Data Type
                string html = "<html><body>" + value + "</body></html>";
                string htmFile = Path.Combine(Path.GetTempPath(), "teamdoctmp.html");
                File.WriteAllText(htmFile, html, UnicodeEncoding.UTF8);
                field.Range.InsertFile(htmFile, ConfirmConversions: false);

                //string s = field.Range.Text;
                //if ("" == field.Range.Words.Last.Text.Trim())
                //{
                //    Word.Range r = field.Range.Words.Last;
                //    field.Range.InsertAfter("\n");
                //    r.Delete();
                //}
                //s = field.Range.Text;

                string htmlfragment = RangeToHtml(clipping, field);

                workItemCustomNode.AppendChildSubtree(string.Format(@"<Field name=""{0}""><![CDATA[{1}]]></Field>"
                    , field.Tag
                    , htmlfragment));
                string debug = workItemCustomNode.LastChild.FirstChild.NodeValue;
            }
            else if (type == FieldType.DateTime)
            {
                if (field.Type == Word.WdContentControlType.wdContentControlDate)
                {
                    field.Range.Text = ((DateTime)value).ToString(field.DateDisplayFormat, new System.Globalization.CultureInfo((int)field.DateDisplayLocale));
                }
                else
                {
                    field.Range.Text = ((DateTime)value).ToString(new System.Globalization.CultureInfo((int)field.Range.LanguageID));
                }
                workItemCustomNode.AppendChildSubtree(string.Format(@"<Field name=""{0}"">{1}</Field>"
                , field.Tag
                , field.Range.Text));
            }
            else if (type == FieldType.Double)
            {
                field.Range.Text = ((double)value).ToString(new System.Globalization.CultureInfo((int)field.Range.LanguageID));
                workItemCustomNode.AppendChildSubtree(string.Format(@"<Field name=""{0}"">{1}</Field>"
                    , field.Tag
                    , field.Range.Text));
            }
            else
            {
                // Other Data Types
                field.Range.Text = value.ToString();
                workItemCustomNode.AppendChildSubtree(string.Format(@"<Field name=""{0}"">{1}</Field>"
                    , field.Tag
                    , field.Range.Text));
            }
        }
        */
    }
}
